package JackCompiler;

import java.io.File;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


public class Parser{

	private static Document doc;
	private SymbolTable symbolTable;

	public Parser(){
		symbolTable = new SymbolTable();
	}

	public void parse(String fileName) throws Exception{
		File fXmlFile = new File(fileName);
		DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
		doc = dBuilder.parse(fXmlFile);
	}

	public void classVarDec(){
		NodeList nList = doc.getElementsByTagName("classVarDec");		
		insertVars(nList);
		System.out.println(symbolTable);
	}

	public void subroutines(){
		NodeList subroutines = doc.getElementsByTagName("subroutineDec");
		for(int i=0; i<subroutines.getLength(); i++){
			
			String name = subroutineName(subroutines.item(i).getChildNodes());
			if(!name.isEmpty())
				System.out.println("Subroutine Name: " + name);
			symbolTable.startSubroutine();
			NodeList parameters = ((Element) subroutines.item(i)).getElementsByTagName("parameterList").item(0).getChildNodes();
			parameterList(parameters);
			NodeList subroutineBody = ((Element) subroutines.item(i)).getElementsByTagName("subroutineBody").item(0).getChildNodes();
			subroutineBody(subroutineBody);
			System.out.println(symbolTable.printSubroutineTable());
		}

	}
	
	public void subroutineBody(NodeList subroutineBody){
			NodeList varDec = ((Element) subroutineBody).getElementsByTagName("varDec");
			System.out.println("lenght: " + varDec.getLength());
			insertVars(varDec);
			
	}
	
	public void parameterList(NodeList parameters){
		ArrayList<String> args = new ArrayList<String>(); 
		for(int k=0; k<parameters.getLength(); k++){
			Node param = parameters.item(k);
			if (param.getNodeType() == Node.ELEMENT_NODE) {
				String item = param.getTextContent().trim();
				if(!item.isEmpty()){
					if(!item.equals(";") && !item.equals(",")){
						args.add(item);
					}
				}
			}
		}
		VarDetails details = new VarDetails();
		details.setKind(SymbolTable.ARG);
		for(int i=0;i<args.size();i+=2){
			details.setType(args.get(i));
			details.setName(args.get(i+1));
			symbolTable.define(details);
		}

	}

	public void localVarDec(NodeList varDec){
		insertVars(varDec);
	}
	
	private String subroutineName(NodeList subroutine){
		return subroutine.item(5).getTextContent().trim();
	}

	private void insertVars(NodeList nList){
		
		ArrayList<ArrayList<String>> args = new ArrayList<ArrayList<String>>();
		for (int temp = 0; temp < nList.getLength(); temp++) {
			NodeList childs = nList.item(temp).getChildNodes();
			ArrayList<String> single = new ArrayList<String>();
			for(int i = 0; i < childs.getLength(); i++){
				Node child = childs.item(i);
				if(child.getNodeType() == Node.ELEMENT_NODE){
					String item = child.getTextContent().trim();
					if(!item.equals(";") && !item.equals(","))
						single.add(item);
				}
			}
			if(single.size() > 0)
				args.add(single);
		}
		
		for(ArrayList<String> single : args){
			VarDetails varDetails = new VarDetails();
			for(int i = 0; i < single.size(); i++){
				String arg = single.get(i);

				switch (i) {
				case 0:
					int kind = -1;
					if(arg.equals("static") ) kind = SymbolTable.STATIC;
					if(arg.equals("field") ) kind = SymbolTable.FIELD;
					if(arg.equals("var") ) kind = SymbolTable.VAR;
					varDetails.setKind(kind);
					break;

				case 1:
					varDetails.setType(arg);
					break;
				default:

					varDetails.setName(arg);
					symbolTable.define(varDetails);
				}

			}
		}

	}
}